package plp.funcoo.environment.execution;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import plp.funcoo.dec.classes.ClassDec;
import plp.funcoo.environment.compilation.Environment;
import plp.funcoo.exceptions.ClassNotDeclared;
import plp.funcoo.exceptions.InvalidInput;
import plp.funcoo.exceptions.ObjectAlreadyDeclared;
import plp.funcoo.exceptions.ObjectNotDeclared;
import plp.funcoo.exceptions.VarNotDeclared;
import plp.funcoo.expressions.Identifier;
import plp.funcoo.util.Type;
import plp.funcoo.value.ValueList;
import plp.funcoo.value.RefValue;
import plp.funcoo.value.Value;

public interface ExecutionEnvironment extends Environment<Value>{

	/**
     * Obtém a pilha de Valuees associados a identificadores
     * @return a pilha de Valuees associados a identificadores.
     */
	public Stack<HashMap<Identifier, Value>> getStack();

    /**
     * Retorna a pilha com as definiçoes das classes.
     * @return a pilha com as definiçoes das classes.
     */
    public HashMap<Identifier, ClassDec> getMapDefClass();

    /**
     * Obtém a pilha com os objetos e seus Valuees.
     * @return a pilha com os objetos e seus Valuees.
     */
    public Stack<HashMap<RefValue, ObjectInstance>> getObjectStack();

    /**
     * Mapeia um Value referência a um objeto.
     * @param ValueRef Value referência.
     * @param objeto Objeto.
     * @throws ObjetoJaDeclaradoException Quando esse objeto já foi declarado.
     */
    public void mapObject(RefValue ValueRef, ObjectInstance objeto) throws ObjectAlreadyDeclared;

    /**
     * Altera o Value associado a um identificador.
     * @param idArg Identificador.
     * @param ValueId O Value a ser associado ao identificador.
     * @throws VariavelNaoDeclaradaException Quando a variável não foi
     * declarada.
     */
    public void changeValue(Identifier idArg, Value ValueId) throws VarNotDeclared;

    /**
     * Obtém o objeto associado a um dado Value referencia.
     * @param ValueRef Value referência
     * @return o objeto associado a um dado Value referencia.
     * @throws ObjetoNaoDeclaradoException Quando o objeto não foi declarado.
     */
    public ObjectInstance getObject(RefValue ValueRef) throws ObjectNotDeclared;

    /**
     * Obtém a próxima referência de acordo com o contexto atual de execução.
     * @return a próxima referência de acordo com o contexto atual de execução.
     */
    public RefValue getNextRef();

    /**
     * Obtém o Value referencia atual.
     * @return o  Value referencia atual.
     */
    public RefValue getRef();

    /**
     * Lê da entrada padrão e associa o conteúdo a um determinado identificador.
     * @param TypeIdLido Type do identificador ao qual será associado o Value
     * lido.
     * @return o Value lido.
     * @throws EntradaInvalidaException Quando a entrada fornecida não pode
     * ser atribuída ao Type do identificador.
     */
    public Value read(Type TypeIdLido) throws InvalidInput;

    /**
     * Escreve um Value 'v' na saída.
     * @param v O Value a ser escrito.
     * @return o ambiente de execução, que representa o estado atual.
     */
    public ExecutionEnvironment write(Value v);

    /**
     * Obtém a entrada.
     * @return a entrada.
     */
    public ValueList getValueInput();

    /**
     * Obtém a saída.
     * @return a saída.
     */
    public ValueList getValueOutput();

    /**
     * Obtém um novo contexto de execução com a mesma entrada, saída e pilha
     * de mapeamentos id/Value.
     * @return um novo contexto de execução com a mesma entrada, saída e pilha
     * de mapeamentos id/Value.
     */
    public ExecutionContext getValueContext();
	
	/**
	 * Mapeia uma classe com a sua super classe
	 * @param classe
	 * @param superClasse
	 * @throws ClasseNaoDeclaradaException Caso a classe mae n‹o tiver sido declarada.
	 */
	public void mapSuperClass(Identifier classe, Identifier superClasse) throws ClassNotDeclared;
	
	/**
	 * Dado um identificador da classe, recupera a super-classe
	 * @param classe identificador da classe base
	 * @return Definicao da super classe
	 * @throws ClasseNaoDeclaradaException Quando a classe ainda nao foi definida
	 */
	public Identifier getSuperClass(Identifier classe) throws ClassNotDeclared;

	/**
	 * Retorna todos os mapeamentos de heran�a do ambiente de execucao
	 * @return
	 */
	public Map<Identifier,Identifier> getMapSuperClass();	
}